Rappel : les bases du langage Python ************************************ Vous pouvez tester en ligne les exemples grâce aux sites suivant : * https://www.online-Python.com/ * https://replit.com/languages/Python3 * https://www.onlinegdb.com/online_Python_compiler Ce chapitre a été mis en place pour les personnes venant d'un autre langage. Il peut être sauté par les personnes familières avec le langage Python. Cependant, le chapitre suivant intitulé *Les pièges du langage Python* doit être consulté par tout le monde. **Dans tous les cas, les questions des QCM doivent être préparées.** Indentation =========== La traditionnelle paire d'accolades a été remplacée en Python par l'indentation. Ainsi, les sources en Python ont une apparence très structurée. En effet, chaque sous-bloc de code est introduit en ajoutant une tabulation ou plusieurs espaces supplémentaires par rapport au bloc parent. A l'intérieur du même bloc, l'indentation doit être identique. Voici le style généré : .. code-block:: py a = 4 # déclaration d'une variable dans le bloc principal def toto(): # définition de la fonction toto() print("toto") # cette ligne appartient au corps de la fonction toto() b = 5 # l'indentation est revenue au niveau de la ligne de l'instruction a=4 => cette ligne appartient au bloc principal def titi(): # définition de la fonction titi() for i in range (10): # indentation supplémentaire => cette boucle appartient à la fonction titi() print(i) # indentation supplémentaire => la fonction print() est dans le corps de boucle print(i) # l'indentation est identique à celle de la ligne précédente => on reste dans le corps de boucle toto() # l'indentation diminue et revient au niveau de la boucle for, cette instruction sera appelée après la fin de la boucle titi() # l'indentation diminue et revient au niveau le plus à gauche, cette ligne appartient au bloc principal Lancement du programme ====================== Stockage dynamique des variables/fonctions ------------------------------------------ En Python, les variables globales, les fonctions, ainsi que les librairies sont créés dynamiquement durant l'exécution du programme. On peut considérer que l'interpréteur Python utilise un dictionnaire pour les stocker les noms de ces différentes entités ; la fonction **vars()** permet ainsi d'afficher la liste des noms déclarés jusqu'ici. L'exécution d'un source Python se déroule ligne à ligne depuis la première ligne du fichier. Lorsque qu'une définition de fonction apparaît, son nom est créé mais en aucun cas cette fonction est exécutée. L'exécution continue à la prochaine ligne du bloc principal, le corps de la fonction n'est pas exécuté. Au lancement, les variables et les fonctions présentes dans votre code n'existent pas encore. .. code-block:: py print(vars()) # (...) a = 5 # création et initialisation de la variable a print(vars()) # { ..., 'a': 5} toto() # cette ligne déclenche une erreur car la fonction toto() est inconnue à ce niveau def toto(): # définit toto() comme fonction print("toto") print(vars()) # { ..., 'a': 5, 'toto': } toto() # cet appel ne déclenche plus d'erreur Import de librairies -------------------- L'import d'une librairie en Python grâce au mot clef **import** entraîne le chargement des fonctions/variables exportées par cette librairie. Les fonctions et les variables exportées par cette librairie deviennent alors accessibles dans le code du programme en utilisant la syntaxe : *nom_librairie.fonction(...)*. .. code-block:: py import numpy # charge la librairie numpy t = numpy.random.rand(3)) # appel de la fonction rand de la librairie numpy .. warning:: Évitez la syntaxe : *from numpy import \** car elle est source de nombreux problèmes insoupçonnables. Il est possible de de choisir un alias pour remplacer le nom de la librairie lors de la commande import : .. code-block:: py import numpy as np t = np.random.rand(3) # écrire np est suffisant pour appeler les fonctions de la librairie Du point de vue technique, on distingue deux scénarios en Python : * Un fichier unique contenant des définitions : on parle alors de **module** simple * Un répertoire contenant plusieurs fichiers ainsi qu'un fichier spécial organisant leurs chargements : on parle alors de **package** .. quiz:: quizzpython2 :title: Mise en pratique Donnez l'affichage produit par le code maladroit suivant : .. code-block:: py def toto(): print("V1") toto() def toto(): print("V2") toto() * A : V1 / V1 * B : V1 / V2 * C : V2 / V1 * D : V2 / V2 * E : erreur :quiz:`{"type":"FB","answer":"B"}` Structures de contrôle ====================== Les branchements ---------------- * Il n'est pas nécessaire de parenthèser les conditions contrairement aux autres langages type C++/Java. * Les mots-clefs **and**, **or** et **not** désignent les opérateurs booléens. * Les constantes booléennes sont : **True** et **False** avec des majuscules. .. code-block:: py for i in range(100): if i % 3 == 0 and i % 7 == 0 : print(i) >> 0 21 42 63 Les boucles ----------- .. code-block:: py for i in range(5): print(i) # 0 1 2 3 4 for i in range(3,10,2): print(i) # 3 5 7 9 .. quiz:: quizzpython3 :title: Mise en pratique Indiquez la valeur de la variable *tot* à la fin du code suivant : .. code-block:: py tot = 0 for i in range(3,11,4): if i > 5 : tot += i :quiz:`{"type":"FB","answer":"7"}` Les containers ============== Immutable / mutable ------------------- Si l'on consulte la `documentation officielle Python `_ on peut trouver cette information : * Objects whose value can change are said to be **mutable** * Objects whose value is unchangeable once they are created are called **immutable** Les listes ---------- Objet Python très commun, la liste permet de stocker et d'indexer plusieurs éléments de types hétérogènes. Les listes permettent d'ajouter ou de retirer des éléments dynamiquement. En contrepartie de cette souplesse, elles sont bien plus lentes que les vecteurs du C++ ou les arrayList du Java. .. list-table:: :widths: 25 50 * - L = [1, 2, 5, 2] - Création et initialisation * - L = [1, \"toto\", 3.1415, [1,2] ] - Création d'une liste contenant des types hétérogènes * - L.append(5) - Ajout de l'élément 5 en fin de liste * - L.insert(2,9) - Insère la valeur 9 à l'index 2 * - L.remove(2) - Retire la première valeur 2 trouvée dans la liste * - L.pop() - Retourne et retire le dernier élément de la liste * - len(L) - Nombre d'éléments dans la liste * - L.sort() - Trie la liste inplace * - L[0] - Accès par indexation * - L.clear() - Vide la liste * - [1, 2] + [4 , 5] - L'opérateur + concatène les deux listes : [1, 2, 4, 5] * - print(L) - Affiche le contenu de la liste Les tuples ---------- Un tuple représente une liste de taille fixe non modifiable une fois créé (immutable). Un tuple peut stocker des éléments de types hétérogènes. .. list-table:: :widths: 25 50 * - L = (1, 2, [4,5]) - Création d'un tuple contenant des types hétérogènes * - len(L) - Nombre d'éléments dans la liste * - L[0] - Accès par indexation * - L[2][0] +=1 - Accès à la valeur 4 de la liste [4,5] => L: (1, 2, [5,5]) * - print(L) - Affiche le contenu du tuple Pour faciliter l'empaquetage et le dépaquetage d'éléments, des syntaxes compactes sont proposées : .. code-block:: py L = (1, 2, [4,5]) x,y,z = L # dépaquetage >> x: 1 >> y: 2 >> z: [5,5] L = x,z # empaquetage >> (2,[5,5]) Les tuples sont sensés être plus performant en rapidité que les listes. En utilisant la syntaxe compacte des tuples, on peut effectuer plusieurs affectations en 1 ligne : .. code-block:: py x,y,z = 1,2,3 Les tuples permettent de retourner plusieurs éléments comme résultat d'une fonction. Cette facilité est très pratique : .. code-block:: py def toto(): return 1,"toto" a,b = toto() .. note:: On trouve des tuples et des listes dans tous les programmes Python. On peut cependant s'interroger sur l'intérêt de proposer ces deux objets très similaires. Il n'est pas toujours évident pour le développeur débutant de savoir quel container choisir. En cas de doute, choisissez une liste. Les dictionnaires ----------------- Un dictionnaire associe une valeur à une clef, clefs comme valeurs peuvent être de types hétérogènes. Ainsi un dictionnaire correspond à une de liste dont les index peuvent être autre chose que des entiers. Les dictionnaires offrent plus de souplesse que les listes, au détriment de la performance. Voici les syntaxes des dictionnaires : .. list-table:: Exemples :widths: 25 50 * - D = { } - Création d'un dictionnaire à partir d'une paire d'accolades * - D[\'PV\'] = 4 - Associe la valeur 4 à la clef PV * - D[\'PV\'] = 8 - Modifie la valeur associée à la clef PV * - D[9] = \'ARC\' - Associe la valeur \'ARC\' à la clef 9 * - print(D) - affiche le contenu du dictionnaire : { \'PV\': 4, 9: \'ARC\'} * - if \'PV\' in D - Teste si la clef PV existe dans le dictionnaire * - L = { \'PV\': 4, \'OR\': 2} - Initialisation d'un dictionnaire par passage de paires clefs/valeurs * - len(L) - Indique le nombre d'entrées ou de clefs dans le dictionnaire Boucle sur les containers ------------------------- On peut parcourir les éléments d'un container s'il est dit **iterable**. Les containers comme les listes, les tuples ou les dictionnaires appartiennent à cette catégorie. On peut ainsi écrire un algorithme à base de boucles for pouvant fonctionner avec différents types de container sans changer le code associé. Voici un exemple : .. code-block:: py def Aff(data): for e in data : # syntaxe du foreach en Python print(e, " / " end="") L = [4,5,6] # container liste Aff(L) >> 4 / 5 / 6 / L = (1,2) # container tuple Aff(L) >> 1 / 2 / L = {'PV': 4, 'OR': 2} # container dictionnaire Aff(L) >> PV / OR / .. quiz:: quizzpython :title: Questionnaire Pour chaque affirmation, indiquez si elle est vraie ou fausse. .. csv-table:: :widths: 40, 10 :delim: ! La fonction len() donne le nombre d'éléments d'une liste, d'un tuple ou d'un dictionnaire ! :quiz:`{"type":"TF","answer":"T"}` On peut modifier le nombre d'éléments d'un tuple. ! :quiz:`{"type":"TF","answer":"F"}` La fonction print() liste les informations stockées dans un container ! :quiz:`{"type":"TF","answer":"T"}` On peut créer une liste contenant des dictionnaires ! :quiz:`{"type":"TF","answer":"T"}` Un tuple contient uniquement des éléments de même type ! :quiz:`{"type":"TF","answer":"F"}` Un même dictionnaire doit contenir uniquement des clefs de même type ! :quiz:`{"type":"TF","answer":"F"}` Dans une liste, on peut insérer un élément uniquement en fin de liste ! :quiz:`{"type":"TF","answer":"F"}` Il est possible de savoir si une clef est déjà utilisée dans un dictionnaire ! :quiz:`{"type":"TF","answer":"T"}` En associant une valeur à une clef, la valeur précédemment associée à cette clef est écrasée ! :quiz:`{"type":"TF","answer":"T"}`